﻿/*
 *   Copyright 2011 Peter Crossley
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 *  ----------------------------------------------------------------------------
 *  File:       Program.cs
 *  Author:     Peter Crossley
 *  ----------------------------------------------------------------------------
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Security.Principal;

namespace UEC
{
    public class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        public static void Main(String[] args)
        {
            try
            {
                CloudManagerSettings cli = Parse(args);

                if (cli.UsageFlag)
                {
                    MessageBox.Show(String.Format(Properties.Resources.UsageHelp, Path.GetFileName(Application.ExecutablePath)), Properties.Resources.uiTitle);
                    return;
                }

                if (cli.Elevate && !cli.Fork && !IsElevated)
                {
                    ElevateProcess(args);
                    return;
                }
                else if (cli.Fork && !cli.Service && !IsElevated)
                {
                    MessageBox.Show(Properties.Resources.UnableToElevate, Properties.Resources.uiTitle);
                    return;
                }

                CloudManager manager = new CloudManager(Application.StartupPath, Application.ExecutablePath, Application.CommonAppDataRegistry, cli);
                manager.Debug = cli.Debug;

                if (cli.Audit && manager.Mode == "audit")
                {
                    manager.LoadUserDataSettings();
                    manager.OnCloudServiceSetProperties();
                    manager.OnCloudServiceSysprepAudit();
                    //wait 20 seconds to reboot
                    manager.OnCloudServiceSystemReboot(20);
                }
                else if (cli.Sysprep && manager.Mode == "sysprep")
                {
                    //Run forcefully --not really used except for debugging
                    manager.LoadUserDataSettings();
                    manager.OnCloudServiceSysprep();
                }
                else if (cli.Service)
                {
                    System.ServiceProcess.ServiceBase.Run(new Service.CloudService(manager));                   
                }
                else if (cli.User)
                {
                    if (manager.Mode != null)
                    {
                        return;
                    }
                    manager.IsUserMode = true;
                    manager.LoadUserDataSettings();
                    manager.OnCloudServiceSetProperties();
                    manager.OnCloudServiceRun();
                }
                else 
                {
                    cli.AppManager = true;
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new ConfigUI.CloudServiceManager(manager));
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(Properties.Resources.uiError + "\n\n" + e.ToString(), Properties.Resources.uiTitle);
            }
        }

        private static void ElevateProcess(String[] args)
        {
            // runs with the same arguments plus flag mentioning the main action performing
            var info = new ProcessStartInfo(Application.ExecutablePath, String.Join(" ", Enumerable.Concat(args, new String[] { "/fork" }).ToArray()))
            {
                Verb = "runas", // indicates to elevate privileges
                UseShellExecute = true //needed so we can do a runas verb
            };

            var process = new Process
            {
                EnableRaisingEvents = true, // enable WaitForExit()
                StartInfo = info
            };

            process.Start();
            process.WaitForExit(); // sleep calling process thread until evoked process exit
        }

        private static bool IsElevated
        {
            get
            {
                return UEC.Support.UacHelper.IsProcessElevated;
            }
        }

        private static CloudManagerSettings Parse(IEnumerable<string> args)
        {
            var settings = new CloudManagerSettings(IsElevated);
            foreach (var arg in args)
            {
                switch (arg)
                {
                    case "/?":
                        {
                            // stop further parsing and return only meaning flag
                            return new CloudManagerSettings() { UsageFlag = true };
                        }
                    case "/service":
                        {
                            settings.Service = true;
                            break;
                        }
                    case "/user":
                        {
                            settings.User = true;
                            break;
                        }
                    case "/audit":
                        {
                            settings.Audit = true;
                            break;
                        }
                    case "/sysprep":
                        {
                            settings.Sysprep = true;
                            break;
                        }
                    case "/debug":
                        {
                            settings.Debug = true;
                            break;
                        }
                    case "/elevate":
                        {
                            settings.Elevate = true;
                            break;
                        }
                    case "/fork":
                        {
                            settings.Fork = true;
                            break;
                        }

                }
            }
            return settings;
        }
    }
}
